package com.defangit.production.orm;


import com.defangit.production.bll.ManufactureEntryBll;
import com.defangit.production.bll.ProcessBll;
import com.defangit.production.domain.*;
import laogen.hibernate.CommonFinder;
import laogen.hibernate.CommonService;
import laogen.lang.exception.ParameterNotValidException;
import org.hibernate.Criteria;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;

import java.time.LocalDateTime;

public class ManufactureEntryService extends CommonService<ManufactureEntry> implements ManufactureEntryBll {

    @Override
    public ManufactureEntry addManufactureEntry(ManufactureEntry manufacture) {
        return null;
    }

    @Override
    public ManufactureEntry addEntry(ManufactureEntry manufactureEntry, Integer operatorId) {
        if (manufactureEntry==null) throw ParameterNotValidException.nullParameter("生产订单信息异常");
        Operator operator = new OperatorService().get(operatorId).orElseThrow(()->ParameterNotValidException.zeroIdOrEntityNonExist("用户信息异常"));
        if (manufactureEntry.getManufactureItems().isEmpty()) throw ParameterNotValidException.nullParameter("完成记录单异常");
        manufactureEntry.setCreateTime(LocalDateTime.now());
        manufactureEntry.setProducer(operator);
        manufactureEntry.setCheckStatus(CheckStatus.TO_BE_CHECK);
        ProductionProcess productionProcess = new ProductionProcessService()
                .get(manufactureEntry.getProductionProcess().getId())
                .orElseThrow(()->ParameterNotValidException.zeroIdOrEntityNonExist("工单信息异常"));
        manufactureEntry.setProductionProcess(productionProcess);
//        manufactureEntry.getManufactureItems().forEach(manufactureItem -> {
//            Stock stock = new StockService()
//                    .findAll()
//                    .manufactureId(manufactureItem.getManufacture().getId())
//                    .storeId(productionProcess.getWorkShop().getId())
//                    .unique()
//                    .orElse(null);
//            if (stock==null){
//                stock = new Stock().setManufacture(manufactureItem.getManufacture()).setStore(productionProcess.getWorkShop());
//                getSession().save(stock);
//            }
//            StockAlteration stockAlteration = new StockAlteration()
//                    .setCreateTime(LocalDateTime.now())
//                    .setFlag(0)
//                    .setManufacture(manufactureItem.getManufacture())
//                    .setQuantity(manufactureEntry.getQuantity())
//                    .setStore(productionProcess.getWorkShop());
//            getSession().save(stockAlteration);
//        });
        add(manufactureEntry);
        commitSession();
        return get(manufactureEntry.getId()).orElseThrow(()->ParameterNotValidException.zeroIdOrEntityNonExist("记录单失效请核对记录信息后尝试重新上传"));
    }

    @Override
    public ManufactureEntry checkEntry(Integer entryId, Integer operatorId,CheckStatus checkStatus,double quantity,String reason) {
        ManufactureEntry manufactureEntry = get(entryId).orElseThrow(()->ParameterNotValidException.zeroIdOrEntityNonExist("记录单信息为空"));
        if (manufactureEntry.getCheckStatus()!=CheckStatus.TO_BE_CHECK) throw ParameterNotValidException.constraintNotSatisfy("记录单质检状态异常","记录单质检状态异常请联系管理员");
        Operator operator = new OperatorService().get(operatorId).orElseThrow(()->ParameterNotValidException.zeroIdOrEntityNonExist("用户信息异常"));
        manufactureEntry.setCheckReason(reason).setCheckStatus(checkStatus).setEndTime(LocalDateTime.now());
        manufactureEntry.getInspectors().add(operator);
        manufactureEntry.getManufactureItems().forEach(manufactureItem -> {
            if (manufactureItem.getQuantity() == quantity){
                manufactureEntry.setCheckStatus(CheckStatus.QUALIFIED);
            } else {
                manufactureEntry.setCheckStatus(CheckStatus.DISQUALIFIED);
            }
        });
        update(manufactureEntry.setQuantity(quantity));
        commitSession();
        return get(entryId).orElseThrow(()->ParameterNotValidException.zeroIdOrEntityNonExist("产品记录单信息获取失败"));
    }

    @Override
    public ManufactureEntry intoStore(Integer entryId, Integer operatorId,Integer storeId) {
        ManufactureEntry manufactureEntry = get(entryId).orElseThrow(()->ParameterNotValidException.zeroIdOrEntityNonExist("完成品记录单信息异常"));
        if (manufactureEntry.getQuantity()<=0){
            throw ParameterNotValidException.constraintNotSatisfy("合格数量异常","合格数量异常无法保存入库信息");
        }
        Operator operator = new OperatorService().get(operatorId).orElseThrow(()->ParameterNotValidException.zeroIdOrEntityNonExist("用户信息异常"));
        Store store = new StoreService().get(storeId).orElseThrow(()->ParameterNotValidException.zeroIdOrEntityNonExist("仓库信息异常"));
        manufactureEntry.setReceiver(operator).setEndTime(LocalDateTime.now()).setStore(store);
        update(manufactureEntry);
        manufactureEntry.getManufactureItems().forEach(manufactureItem -> {
            Stock stock = new StockService()
                    .findAll()
                    .manufactureId(manufactureItem.getManufacture().getId())
                    .storeId(store.getId())
                    .unique()
                    .orElse(null);
            if (stock==null){
                stock = new Stock().setManufacture(manufactureItem.getManufacture()).setStore(store);
                getSession().save(stock);
            }
            StockAlteration stockAlterationAdd = new StockAlteration()
                    .setCreateTime(LocalDateTime.now())
                    .setFlag(0)
                    .setManufacture(manufactureItem.getManufacture())
                    .setQuantity(manufactureEntry.getQuantity())
                    .setStore(store);
            getSession().save(stockAlterationAdd);
//            StockAlteration stockAlterationReduce = new StockAlteration()
//                    .setCreateTime(LocalDateTime.now())
//                    .setFlag(1)
//                    .setManufacture(manufactureItem.getManufacture())
//                    .setQuantity(manufactureEntry.getQuantity())
//                    .setStore(manufactureEntry.getProductionProcess().getWorkShop());
//            getSession().save(stockAlterationReduce);
        });
        commitSession();
        return get(entryId).orElseThrow(()->ParameterNotValidException.zeroIdOrEntityNonExist("完成品记录单信息异常"));
    }

    @Override
    public ManufactureEntry updateManufactureEntry(ManufactureEntry manufacture, Integer operatorId) {
        return null;
    }

    @Override
    public ManufactureEntry fixProcess(Integer entryId, Integer processId, Integer operatorId) {
        ManufactureEntry manufactureEntry = get(entryId).orElseThrow(()->ParameterNotValidException.zeroIdOrEntityNonExist("记录单异常"));
        ProductionProcess productionProcess = new ProductionProcessService().get(processId).orElseThrow(()->ParameterNotValidException.zeroIdOrEntityNonExist("工单信息异常"));
        Operator operator = new OperatorService().get(operatorId).orElseThrow(()->ParameterNotValidException.zeroIdOrEntityNonExist("用户信息异常"));
        if (operator.getId()!=manufactureEntry.getProducer().getId()) throw ParameterNotValidException.constraintNotSatisfy("用户权限不足","the user can not update it");
        manufactureEntry.setProductionProcess(productionProcess);
        update(manufactureEntry);
        commitSession();
        return get(entryId).orElseThrow(()->ParameterNotValidException.zeroIdOrEntityNonExist("产品记录单获取失败"));
    }


    @Override
    public ManufactureEntryFinder findAll() {

        return new ManufactureEntryFinderImp();
    }

    public class ManufactureEntryFinderImp extends CommonFinder<ManufactureEntry> implements ManufactureEntryFinder {
        private DetachedCriteria entryCriteria;

        private ManufactureEntryFinderImp(){
            this.entryCriteria = detachedAll();
        }

        @Override
        public Criteria getCriteria() {
            return this.entryCriteria.getExecutableCriteria(getSession()).addOrder(Order.desc("id"));
        }

        @Override
        public DetachedCriteria getDetachedCriteria() {
            return this.entryCriteria;
        }

        @Override
        public ManufactureEntryFinder entryNo(String no) {
            this.entryCriteria.add(Restrictions.eq("no",no));
            return this;
        }

        @Override
        public ManufactureEntryFinder entryStaus(CheckStatus checkStatus) {
            if (checkStatus==null) return this;
            this.entryCriteria.add(Restrictions.eq("checkStatus",checkStatus));
            return this;
        }

        @Override
        public ManufactureEntryFinder entryProcess(Integer processId) {
            if (processId==null) return this;
            this.entryCriteria.add(Restrictions.eq("productionProcess.id",processId));
            return this;
        }

        @Override
        public ManufactureEntryFinder storeNull(Boolean isNull) {
            if (isNull==null) {
                return this;
            }
            if (isNull){
                this.entryCriteria.add(Restrictions.isNull("store"));
            } else {
                this.entryCriteria.add(Restrictions.isNotNull("store"));
            }
            return this;
        }

        public ManufactureEntryFinder producerId(Integer operatorId) {
            if(operatorId==null) return this;
            this.entryCriteria.add(Restrictions.eq("producer.id",operatorId));
            return this;
        }

        public ManufactureEntryFinder storeId(Integer storeId) {
            if (storeId==null) return this;
            this.entryCriteria.add(Restrictions.eq("store.id",storeId));
            return this;
        }

        public ManufactureEntryFinder receiverId(Integer receiveId) {
            if (receiveId==null) return this;
            this.entryCriteria.add(Restrictions.eq("receiver.id",receiveId));
            return this;
        }

        public ManufactureEntryFinder inspectorsId(Integer inspectorId) {
            if (inspectorId==null) return this;
            this.entryCriteria.createAlias("inspectors","inspector")
                    .add(Restrictions.eq("inspector.id",inspectorId));
            return this;
        }
    }
}
